import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;


/*** GuiCommands - in charge of  running commands arriving from GUI listeners ***/
public class GuiCommands {
	private Simulation sim;
	private Canvas canvas;
	
	private Shell shell;
	private  Programs programs; //in charge of threads that run robot progs during simulation
	
	private MyThread thread = null; //runs timer
	
	//c'tor
	public GuiCommands(Simulation sim, Canvas c, Shell s, Programs p){
		programs = p;
		this.sim = sim;
		canvas = c;
		shell = s;
	}
	
	//method assigns robot with file if possible
	public boolean assign(String r_name, String f_name){
		
		 //check if has file already
		 if(sim.getRobot(r_name).hasFile()){
			 GUI.errorMessage("Error: another program is assigned to this robot.");
			 return false;
		 }
		 //check if selected file is a .txt file
		 if(!f_name.matches("(\\w+).txt")){
			 GUI.errorMessage("Error: file not found.");
			 return false;
		 }
		 
		 Robot r = sim.getRobot(r_name);
		 r.setFileName(f_name);
		 r.setHasFile(true);
		 programs.add(new RunProgram(r, f_name, sim.boxes));
		 return true;
	}
	
	//method  tries to add robot and returns 1 if succeeds
	public boolean addRobot(final String name, final String type, final GUI.Addition add){
	
		if(sim.nameExists(name)){
			GUI.errorMessage("Error: Robot with this name already exists");
			return false;
		}
		//insert robot to simulation according to addintion type
		switch(add){
	 	case ALL: 
	 		sim.insertRobot(new ArmAddition(new SmartRobot(sim.createRobot(type, name, 0, 0))));
	 		break;
	
	 	case SMART:
	 		sim.insertRobot(new SmartRobot(sim.createRobot(type, name, 0, 0)));
	 		break;
		
	 	case ARM:
	 		sim.insertRobot(new ArmAddition(sim.createRobot(type, name, 0, 0)));
	 		break;
	 		
	 	default:
	 		sim.insertRobot(sim.createRobot(type, name, 0, 0));
	 		break;
		}//switch
	canvas.redraw();
	return true;
	}
	
	//method adds box
	public void addBox(){
		//insert position window
	    Shell s = new Shell(shell);
	    s.setLayout(new GridLayout(2,false));
	    s.setText("New box information");
	    s.setSize(200, 150);
	    s.setLocation(300, 250);
	    
	    new Label(s,SWT.NONE).setText("name");
	    final Text name = new Text(s, SWT.SINGLE | SWT.BORDER);
	    name.setText("box_name");
	    
	    new Label(s,SWT.NONE).setText("X coordinate");
	    final Text x = new Text(s, SWT.SINGLE | SWT.BORDER);
	    
	    new Label(s,SWT.NONE).setText("Y coordinate");
	    final Text y = new Text(s, SWT.SINGLE | SWT.BORDER);
	    
	    Button okButton = new Button(s, SWT.PUSH);
	    okButton.setText("OK");
	    
	    Button cancelB = new Button(s, SWT.PUSH);
	    cancelB.setText("Cancel");
	  
	    s.open();
	    
	    //pressed OK
	    okButton.addSelectionListener(new SelectionListener(){
	    	public void widgetSelected(SelectionEvent e){
	    		
	    		if(!x.getText().matches("(-?\\d+)") || !y.getText().matches("(-?\\d+)")){
	    			GUI.errorMessage("enter integer coordinates");
	    			return;
	    		}
	    		
	    		String boxName = name.getText();
	    		int x_i = Integer.parseInt(x.getText());
	    		int y_i = Integer.parseInt(y.getText());
	    		
	    		//check that box doesn't already exist
	    		if(!sim.boxes.exists(boxName)){
	    			Box box = new Box(boxName, new Position(x_i, y_i));
					sim.boxes.addBox(box);
			    	canvas.redraw();
			    	e.display.getActiveShell().dispose(); // close window
	    		} 
	    		else
	    			GUI.errorMessage("Box by that name allready exists");
	    		
	    	}
	    	 public void widgetDefaultSelected(SelectionEvent e){}
	    });
	    
	    //pressed cancel
	    cancelB.addSelectionListener(new SelectionListener(){
	    	public void widgetSelected(SelectionEvent e){
	    		e.display.getActiveShell().dispose();
	    	}
	    	 public void widgetDefaultSelected(SelectionEvent e){}
	    });
	}
	
	
	/**_______________________________________________________________________________________**/
	//timerTask - redraws canvas
	private class RedrawTask extends TimerTask{
		 Canvas c;
		 Display d;
		 
		 public void setCanvas(Canvas c){
		  this.c=c;
		  d=c.getDisplay();
		 }
		 @Override
		 public void run() {  
			 d.asyncExec(new Runnable(){
				 public void run() {
					 if(!c.isDisposed()){
						 c.redraw();
						 c.update();
					 }
				 }
			 });
		 }
		}
	
	// a thread that runs the timerTask every second
	private class MyThread extends Thread{
	 private RedrawTask rt;
	 private Timer ti;
		public void run(){
		 	rt = new RedrawTask();
		    rt.setCanvas(canvas);
			ti = new Timer();
			ti.scheduleAtFixedRate(rt, 0, 1000);
	     }
	 public void end(){
		 rt.cancel();
		 ti.cancel();
	 }
	}
	/**_________________________________________________________________________________________**/
	
	//method starts simulation
	public void simulate(){
		Display display = shell.getDisplay();
		
		thread = new MyThread();
		thread.start(); //start timer
		programs.run();
		
		// Set up the event loop.
	    while (!shell.isDisposed()) {
	      if (!display.readAndDispatch()) {
	        // If no more entries in the event queue
	        display.sleep();
	      }
	    }
	    if(thread != null)
	    	thread.end();//end timer thread
	    GUI.stopSim(); //stops all threads on programs
	    display.dispose();
	}	
	
	//method stops sim
	public void stopSimulation(){
		if(thread != null){
			  thread.end();
			  thread = null;
		  }
	}
}
